﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace Admin2020.Core.Helper
{
    public class CryptoHelper
    {
        public const int SALT_BYTE_SIZE = 16;
        public const int HASH_BYTE_SIZE = 32;
        public const int PBKDF2_ITERATIONS = 1000;

        public const int ITERATION_INDEX = 0;
        public const int SALT_INDEX = 1;
        public const int PBKDF2_INDEX = 2;

        public static string GetRandomSalt()
        {
            RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
            byte[] salt = new byte[SALT_BYTE_SIZE];
            csprng.GetBytes(salt);

            return Convert.ToBase64String(salt);
        }

        public static string HashPassword(string password, string saltString)
        {
            byte[] salt = Convert.FromBase64String(saltString);

            // 初始化
            var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, PBKDF2_ITERATIONS);
            byte[] hash = rfc2898DeriveBytes.GetBytes(HASH_BYTE_SIZE);

            byte[] inArray = new byte[49];
            Buffer.BlockCopy((Array)salt, 0, (Array)inArray, 1, 16);
            Buffer.BlockCopy((Array)hash, 0, (Array)inArray, 17, 32);
            return Convert.ToBase64String(hash);
        }

        public static bool VerifyHashedPassword(string hashedPassword, string password, string saltString)
        {
            if (hashedPassword == null)
                return false;
            if (password == null)
                throw new ArgumentNullException("password");
            byte[] numArray = Convert.FromBase64String(hashedPassword);

            var hash = HashPassword(password, saltString);
            var bytes = Convert.FromBase64String(hash);
            var hashedPasswordBytes = Convert.FromBase64String(hashedPassword);
            return CryptoHelper.ByteArraysEqual(bytes, hashedPasswordBytes);



            //byte[] numArray = Convert.FromBase64String(hashedPassword);
            //if (numArray.Length != 49 || (int)numArray[0] != 0)
            //    return false;
            //byte[] salt = new byte[16];
            //Buffer.BlockCopy((Array)numArray, 1, (Array)salt, 0, 16);
            //byte[] a = new byte[32];
            //Buffer.BlockCopy((Array)numArray, 17, (Array)a, 0, 32);
            //byte[] bytes;
            //using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, 1000))
            //    bytes = rfc2898DeriveBytes.GetBytes(32);
            //return Crypto.ByteArraysEqual(a, bytes);
        }

        private static bool ByteArraysEqual(byte[] a, byte[] b)
        {
            if (object.ReferenceEquals((object)a, (object)b))
                return true;
            if (a == null || b == null || a.Length != b.Length)
                return false;
            bool flag = true;
            for (int index = 0; index < a.Length; ++index)
            {
                flag &= (int)a[index] == (int)b[index];
            }
            return flag;
        }
    }
}
